import { _decorator, Component, Node, NodePool, __private, IPoolHandlerComponent, Prefab, instantiate } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('Pool')
export class Pool<T extends Component> {

    private _prefab: Prefab = null;
    private _nodePool: NodePool = null;
    private _poolHandlerComp: any = null;

    public constructor(
        prefab,
        poolHandlerComp?: string | __private._extensions_ccpool_node_pool__Constructor<IPoolHandlerComponent>,
        initCount?: number
    ) {
        this._prefab = prefab;
        this._poolHandlerComp = poolHandlerComp;
        this._nodePool = new NodePool(poolHandlerComp);
        if (initCount > 0) {
            for (let i = 0; i < initCount; i++) {
                let node = instantiate(this._prefab);
                this._nodePool.put(node);
            }
        }
    }

    public destroy() {
        this._nodePool.clear();
        this._nodePool = null;
    }

    public getNodeFromPool(parent?: Node): Node {
        let node: Node = null;
        if (this._nodePool.size() > 0) {
            node = this._nodePool.get();
        } else {
            node = instantiate(this._prefab);
        }
        if (!!parent) parent.addChild(node);
        return node;
    }

    public getFromPool(parent?: Node): T {
        let node = this.getNodeFromPool(parent);
        let ps = node.getComponent(this._poolHandlerComp);
        return ps as T;
    }

    public putNodeToPool(node: Node) {
        this._nodePool.put(node);
    }

    public putToPool(ps: T) {
        this._nodePool.put(ps.node);
    }

    public putAllChildrenToPool(node: Node) {
        let choosed: Node[] = [];
        node.children.forEach(_ => {
            if (_.getComponent(this._poolHandlerComp) != null) {
                choosed.push(_);
            }
        });
        choosed.forEach(_ => this.putNodeToPool(_));
    }
}

